home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload Trio 2
/
Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO
/
dir24
/
jnos110g.zip
/
NRCMD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-26
|
47KB
|
1,732 lines
/* net/rom user command processing
* Copyright 1989 by Daniel M. Frank, W9NK. Permission granted for
* non-commercial distribution only.
*/
/* Mods by G1EMM, PA0GRI and WG7J */
#include <ctype.h>
#include <time.h>
#ifdef MSDOS
#include <dos.h>
#endif
#include "global.h"
#ifdef NETROM
#include "mbuf.h"
#include "ax25.h"
#include "mailbox.h"
#include "netrom.h"
#include "nr4.h"
#include "timer.h"
#include "iface.h"
#include "pktdrvr.h"
#include "lapb.h"
#include "cmdparse.h"
#include "session.h"
#include "socket.h"
#include "commands.h"
#include "files.h"
int G8bpq;
int Nr_hidden = 1;
unsigned Nr_sorttype = 1;
char Nr4user[AXALEN];
char *Nr4states[] = {
"Disconnected",
"Conn Pending",
"Connected",
"Disc Pending",
"Listening"
} ;
char *Nr4reasons[] = {
"Normal",
"By Peer",
"Timeout",
"Reset",
"Refused"
} ;
static int dobcnodes __ARGS((int argc,char *argv[],void *p));
static int dobcpoll __ARGS((int argc,char *argv[],void *p));
static int dointerface __ARGS((int argc,char *argv[],void *p));
static int donfadd __ARGS((int argc,char *argv[],void *p));
static int donfdrop __ARGS((int argc,char *argv[],void *p));
static int donfdump __ARGS((void));
static int donfmode __ARGS((int argc,char *argv[],void *p));
static int donodefilter __ARGS((int argc,char *argv[],void *p));
static int donodetimer __ARGS((int argc,char *argv[],void *p));
extern int donralias __ARGS((int argc,char *argv[],void *p));
static int donracktime __ARGS((int argc,char *argv[],void *p));
static int donrmycall __ARGS((int argc,char *argv[],void *p));
static int donrchoketime __ARGS((int argc,char *argv[],void *p));
static int donrconnect __ARGS((int argc,char *argv[],void *p));
static int donrirtt __ARGS((int argc,char *argv[],void *p));
static int donrkick __ARGS((int argc,char *argv[],void *p));
static int dorouteadd __ARGS((int argc,char *argv[],void *p));
static int doroutedrop __ARGS((int argc,char *argv[],void *p));
static int donrqlimit __ARGS((int argc,char *argv[],void *p));
static int donrreset __ARGS((int argc,char *argv[],void *p));
static int donrretries __ARGS((int argc,char *argv[],void *p));
static int donrroute __ARGS((int argc,char *argv[],void *p));
int donrstatus __ARGS((int argc,char *argv[],void *p));
static int donrsave __ARGS((int argc,char *argv[],void *p));
static int donrload __ARGS((int argc,char *argv[],void *p));
static int donrttl __ARGS((int argc,char *argv[],void *p));
static int donruser __ARGS((int argc,char *argv[],void *p));
static int donrwindow __ARGS((int argc,char *argv[],void *p));
void doobsotick __ARGS((void));
static int doobsotimer __ARGS((int argc,char *argv[],void *p));
static int dominquality __ARGS((int argc,char *argv[],void *p));
static int donrtype __ARGS((int argc,char *argv[],void *p));
static int donrpromisc __ARGS((int argc,char *argv[],void *p));
static int donrderate __ARGS((int argc,char *argv[],void *p));
static int doroutesort __ARGS((int argc,char *argv[],void *p));
static int donrhidden __ARGS((int argc,char *argv[],void *p));
static int donrg8bpq __ARGS((int argc,char *argv[],void *p));
static void doallinfo __ARGS((void));
int donrneighbour __ARGS((int argc,char *argv[],void *p));
extern int donr4tdisc __ARGS((int argc,char *argv[],void *p));
extern struct nr_bind *find_best __ARGS((struct nr_bind *list,unsigned obso));
extern struct nr_bind *find_bind __ARGS((struct nr_bind *list,struct nrnbr_tab *np));
extern void nrresetlinks(struct nrroute_tab *rp);
static struct cmds DFAR Nrcmds[] = {
"acktime", donracktime, 0, 0, NULLCHAR,
"alias", donralias, 0, 0, NULLCHAR,
"bcnodes", dobcnodes, 0, 2, "netrom bcnodes <iface>",
"bcpoll", dobcpoll, 0, 2, "netrom bcpoll <iface>",
#ifdef NETROMSESSION
"connect", donrconnect, 1024, 2, "netrom connect <node>",
#endif
"call", donrmycall, 0, 0, NULLCHAR,
"choketime", donrchoketime, 0, 0, NULLCHAR,
"derate", donrderate, 0, 0, NULLCHAR,
#ifdef G8BPQ
"g8bpq", donrg8bpq, 0, 0, NULLCHAR,
#endif
"hidden", donrhidden, 0, 0, NULLCHAR,
"interface", dointerface, 0, 0, NULLCHAR,
"irtt", donrirtt, 0, 0, NULLCHAR,
"kick", donrkick, 0, 2, "netrom kick <&nrcb>",
"load", donrload, 0, 0, NULLCHAR,
"minquality", dominquality, 0, 0, NULLCHAR,
"neighbour", donrneighbour, 0, 0, NULLCHAR,
"nodefilter", donodefilter, 0, 0, NULLCHAR,
"nodetimer", donodetimer, 0, 0, NULLCHAR,
"obsotimer", doobsotimer, 0, 0, NULLCHAR,
"promiscuous", donrpromisc, 0, 0, NULLCHAR,
"qlimit", donrqlimit, 0, 0, NULLCHAR,
"route", donrroute, 0, 0, NULLCHAR,
"reset", donrreset, 0, 2, "netrom reset <&nrcb>",
"retries", donrretries, 0, 0, NULLCHAR,
"status", donrstatus, 0, 0, NULLCHAR,
"save", donrsave, 0, 0, NULLCHAR,
#if defined NETROMSESSION && defined SPLITSCREEN
"split", donrconnect, 1024, 2, "netrom split <node>",
#endif
"timertype", donrtype, 0, 0, NULLCHAR,
"ttl", donrttl, 0, 0, NULLCHAR,
#ifdef NR4TDISC
"tdisc", donr4tdisc, 0, 0, NULLCHAR,
#endif
"user", donruser, 0, 0, NULLCHAR,
"window", donrwindow, 0, 0, NULLCHAR,
NULLCHAR,
} ;
struct timer Nodetimer ; /* timer for nodes broadcasts */
struct timer Obsotimer ; /* timer for aging routes */
/* Command multiplexer */
int
donetrom(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
return subcmd(Nrcmds,argc,argv,p) ;
}
static struct cmds Routecmds[] = {
"add", dorouteadd, 0, 6,
"netrom route add <alias> <destination> <interface> <quality> <neighbor>",
"drop", doroutedrop, 0, 4,
"netrom route drop <destination> <neighbor> <interface>",
"info", dorouteinfo, 0, 0,
"",
"sort", doroutesort, 0, 1,
"",
NULLCHAR,
} ;
/* Route command multiplexer */
static int
donrroute(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
if(argc < 2) {
doroutedump() ;
return 0 ;
}
return subcmd(Routecmds,argc,argv,p) ;
}
/* Code to sort Netrom node listing
* D. Crompton 2/92
* Dump a list of known netrom routes in
* sorted order determined by sort
* flag - default = sort by alias
*/
int
doroutedump()
{
extern unsigned Nr_sorttype;
register struct nrroute_tab *rp ;
register int i,j,k, column ;
char buf[17] ;
char *cp,*temp ;
column = 1 ;
for(i = 0,j=0 ; i < NRNUMCHAINS ; i++)
for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ;j++,rp = rp->next);
#define RTSIZE 17
if (j) {
/* Allocate maximum size */
temp = mallocw (j*RTSIZE);
for(i = 0,j=0,k=0 ; i < NRNUMCHAINS ; i++) {
for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
if(!Nr_hidden && *rp->alias == '#')
continue;
if (Nr_sorttype) {
strcpy(buf,rp->alias) ;
/* remove trailing spaces */
if((cp = strchr(buf,' ')) == NULLCHAR)
cp = &buf[strlen(buf)] ;
if(cp != buf) /* don't include colon for null alias */
*cp++ = ':' ;
pax25(cp,rp->call) ;
} else {
pax25(buf,rp->call);
cp=&buf[strlen(buf)];
*cp++=':';
strcpy(cp,rp->alias);
}
sprintf(&temp[k],"%-16.16s",buf);
k+=RTSIZE;
j++; /* number actually shown */
}
}
#ifdef LINUX
qsort(temp,(size_t)j,RTSIZE,(int (*)__ARGS((void*,void*))) strcmp);
#else
qsort(temp,(size_t)j,RTSIZE,(int (*) ()) strcmp);
#endif
for (i=0,k=0;i<j;i++,k+=RTSIZE) {
tprintf("%-16s ",&temp[k]) ;
if(column++ == 4) {
if(tputc('\n') == EOF) {
free(temp);
return 0;
}
column = 1 ;
}
}
if(column != 1)
tputc('\n') ;
free(temp);
}
return 0 ;
}
/* netrom Route Dump Sort - ALIAS or CALL first */
static int
doroutesort(argc,argv,p)
int argc ;
char *argv[] ;
void *p ;
{
extern unsigned Nr_sorttype;
if(argc < 2) {
tprintf("Netrom Sort by %s\n", Nr_sorttype ? "Alias" : "Call" ) ;
return 0 ;
}
switch(argv[1][0]) {
case 'A':
case 'a':
Nr_sorttype = 1 ;
break ;
case 'C':
case 'c':
Nr_sorttype = 0 ;
break ;
default:
tputs("usage: netrom sort [alias|call]\n") ;
return -1 ;
}
return 0 ;
}
/* Print detailed information on ALL routes (sorted) */
/* D. Crompton */
static void
doallinfo()
{
extern unsigned Nr_sorttype;
register struct nrroute_tab *rp ;
register struct nr_bind *bp ;
register struct nrnbr_tab *np ;
char neighbor[AXBUF] ;
char buf[17];
char *cp,*temp;
int i,j,k, flow_tmp;
flow_tmp=Current->flowmode;
Current->flowmode=1;
for (i=0,j=0;i<NRNUMCHAINS;i++)
for (rp=Nrroute_tab[i];rp!=NULLNRRTAB;rp= rp->next)
for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next,j++);
#define STRSIZE 72
if(j) {
temp=mallocw (j*STRSIZE);
for (i=0,k=0;i<NRNUMCHAINS;i++)
for (rp=Nrroute_tab[i];rp!=NULLNRRTAB;rp= rp->next)
for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next,k+=STRSIZE) {
np = bp->via ;
if (Nr_sorttype) {
strcpy(buf,rp->alias) ;
if((cp = strchr(buf,' ')) == NULLCHAR)
cp = &buf[strlen(buf)] ;
if(cp != buf)
*cp++ = ':' ;
pax25(cp,rp->call) ;
} else {
pax25(buf,rp->call);
cp=&buf[strlen(buf)];
*cp++=':';
strcpy(cp,rp->alias);
}
/* NOTE:
* IF you change the size of this sprintf buffer,
* ALSO change the size of the STRSIZE define above !!!
*/
sprintf(&temp[k],"%-16s %s %3d %3d %-8s %-9s %c %-5u",buf,
rp->flags & G8BPQ_NODEMASK ? "(BPQ)" : " ",
bp->quality,bp->obsocnt,
np->iface->name,
pax25(neighbor,np->call),
(bp->flags & NRB_PERMANENT ? 'P' :
bp->flags & NRB_RECORDED ? 'R' : 'B'),bp->usage);
if(rp->flags & G8BPQ_NODETTL) {
sprintf(buf," %u\n",rp->hops);
strcat(&temp[k],buf);
} else
strcat(&temp[k],"\n");
}
#ifdef LINUX
qsort(temp,(size_t)j,STRSIZE,(int (*)__ARGS((void*,void*))) strcmp);
#else
qsort(temp,(size_t)j,STRSIZE,(int (*) ()) strcmp);
#endif
for(i=0,k=0;i<j;i++,k+=STRSIZE)
if (tputs(&temp[k])==EOF)
break;
free(temp);
Current->flowmode=flow_tmp;
}
}
/* Find the interface, and check if it is active for netrom */
struct iface *FindNrIface(char *name) {
struct iface *ifp;
if((ifp = if_lookup(name)) == NULLIF) {
tprintf(Badinterface,name);
return NULLIF;
}
if(!(ifp->flags & IS_NR_IFACE)) {
tprintf("%s is not active for netrom\n",name);
return NULLIF;
}
return ifp;
}
/* print detailed information on an individual route
* Shows alias as well - WG7J
*/
int
dorouteinfo(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
char *cp;
register struct nrroute_tab *rp ;
register struct nrroute_tab *npp;
struct nr_bind *bp ;
struct nrnbr_tab *np ;
char destbuf[AXBUF];
char neighbor[AXBUF] ;
char alias[AXALEN];
char buf[AXALEN];
char nb_alias[AXALEN];
int print_header=1;
int16 rhash;
if(argc == 1) {
doallinfo();
return 0;
}
putalias(alias,argv[1],0);
strupr(argv[1]); /*make sure it's upper case*/
if((rp = find_nrboth(alias,argv[1])) == NULLNRRTAB){
/*no such call or node alias*/
tputs("no such node\n\n");
return 0;
}
/*copy the real alias*/
strcpy(buf,rp->alias) ;
if((cp = strchr(buf,' ')) != NULLCHAR)
*cp = '\0';
for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
np = bp->via ;
/* now we have to find the alias of the neighbour used
* so we can print that as well!
*/
rhash = nrhash(np->call);
for(npp=Nrroute_tab[rhash];npp!=NULLNRRTAB;npp=npp->next)
if(addreq(npp->call,np->call))
break;
/* found, now remove trailing spaces */
strcpy(nb_alias,npp->alias) ;
if((cp = strchr(nb_alias,' ')) != NULLCHAR)
*cp = '\0';
if(print_header) {
print_header = 0;
tputs(" Node "
#ifdef G8BPQ
" "
#endif
" Neighbour"
#ifdef G8BPQ
" "
#endif
" Port Qual Obs Type Usage"
#ifdef G8BPQ
" Hops Irtt"
#endif
"\n");
tprintf("%6s:%-9s "
#ifdef G8BPQ
"%s "
#endif
,buf,pax25(destbuf,rp->call)
#ifdef G8BPQ
,rp->flags & G8BPQ_NODEMASK ? "(BPQ)" : " "
#endif
);
} else
tputs(" ");
tprintf("%6s:%-9s "
#ifdef G8BPQ
"%s "
#endif
"%-6s %3d %3d %c %-5u",
nb_alias,pax25(neighbor,np->call),
#ifdef G8BPQ
npp->flags & G8BPQ_NODEMASK ? "(BPQ)" : " ",
#endif
np->iface->name,
bp->quality,bp->obsocnt,
bp->flags & NRB_PERMANENT ? 'P' : \
(bp->flags & NRB_RECORDED ? 'R' : 'B'),bp->usage );
#ifdef G8BPQ
if(npp->hops || npp->irtt) {
if(npp->hops)
tprintf(" %3u",npp->hops);
else
tputs( " ");
if(npp->irtt)
tprintf(" %u",npp->irtt);
}
#endif
tputc('\n');
}
tputc('\n');
return 0 ;
}
int
donrneighbour(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int i,printheader=1;
struct nrnbr_tab *np;
struct nrroute_tab *rp;
struct nr_bind *bind;
int16 rhash;
int justused;
char tmp[AXBUF];
char alias[AXALEN];
char *cp;
int percentage;
int quality = 0;
int obsocnt = 0;
#ifdef G8BPQ
unsigned int irtt;
#endif
for(i=0;i<NRNUMCHAINS;i++) { /*loop through all chains of neighbours*/
for(np=Nrnbr_tab[i];np!=NULLNTAB;np=np->next) {
/* If the interface is hidden, then do not show the route */
/*
if(np->iface->flags & HIDE_PORT && Curproc->input != Command->input)
continue;
*/
if(printheader) {
tputs("Routes :\n" \
" Neighbour Port Qual Obs Dest Tries Retries Perc"
#ifdef G8BPQ
" Irtt"
#endif
"\n");
printheader = 0;
}
/* has this one been used recently ? */
if((secclock() - np->lastsent) < 60)
justused = 1;
else
justused = 0;
/* now we have to find the alias of this neighbour
* so we can print that as well!
*/
rhash = nrhash(np->call);
for(rp=Nrroute_tab[rhash];rp!=NULLNRRTAB;rp=rp->next)
if(addreq(rp->call,np->call))
break;
if(rp != NULLNRRTAB) {
/* found, now remove trailing spaces */
strcpy(alias,rp->alias) ;
if((cp = strchr(alias,' ')) != NULLCHAR)
*cp = '\0';
/*find the quality for this neighbour*/
bind = find_bind(rp->routes,np);
if(bind) {
quality = bind->quality;
obsocnt = bind->obsocnt;
} else // should never happen !
quality = obsocnt = 0;
#ifdef G8BPQ
irtt = rp->irtt;
#endif
} else {
strcpy(alias,"##TEMP");
}
if(np->tries)
percentage = (int)( (((long)(np->tries)) * 100L) /
((long)((long)np->tries + (long)np->retries)) );
else
percentage = 0;
/* print it all out */
tprintf("%c %6s:%-9s %s %-6s %3d %3d %3d %-5u %-5u %2d %%",
(justused) ? '>' : ' ',
alias,pax25(tmp,np->call),
rp->flags & G8BPQ_NODEMASK ? "(BPQ)" : " ",
np->iface->name,
quality,obsocnt,np->refcnt,np->tries,np->retries,percentage);
if(irtt)
tprintf(" %u\n",irtt);
else
tputc('\n');
}
}
if(!printheader)
tputc('\n');
return 0;
}
/* define the netrom call,
* this simply changes the interface linkaddress!
* but is a little easier to use...
*/
static int
donrmycall(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
int len;
char tmp[AXBUF];
if(Nr_iface == NULLIF) {
tputs("Attach netrom interface first\n") ;
return 1 ;
}
if(argc < 2) {
if (Nr_iface->hwaddr == NULLCHAR)
tputs("not set\n");
else
tprintf("%s\n",pax25(tmp,Nr_iface->hwaddr));
} else {
if( (len=strlen(argv[1])) > (AXBUF - 1)) {
tputs("too long\n");
return 1;
}
if(Nr_iface->hwaddr != NULLCHAR)
free(Nr_iface->hwaddr);
Nr_iface->hwaddr = mallocw(AXALEN);
setcall(Nr_iface->hwaddr,argv[1]);
#ifdef MAILBOX
setmbnrid();
#endif
}
return 0;
}
/* make an interface available to net/rom */
/* arguments are:
* argv[0] - "interface"
* argv[1] - "iface" , the interface name
* argv[2] - "quality", the interface broadcast quality
* argv[3] - "n" or "v", to override the default (verbose)
* n = never broadcast verbose
* v = always broadcast verbose
*/
static
int
dointerface(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct iface *ifp ;
int i,mtu ;
if(Nr_iface == NULLIF) {
tputs("Attach netrom interface first\n") ;
return 1 ;
}
if(argc < 3) {
i = 0;
for(ifp=Ifaces;ifp;ifp=ifp->next) {
if(ifp->flags & IS_NR_IFACE){
if(!i) {
i = 1;
tputs("Iface Qual MinBcQual\n");
}
tprintf("%-6s %-3d %d\n",
ifp->name,ifp->quality,ifp->nr_autofloor);
}
}
return 0;
}
if((ifp = if_lookup(argv[1])) == NULLIF){
tprintf(Badinterface,argv[1]);
return 1;
}
if(ifp->type != CL_AX25){
tprintf("Interface %s is not NETROM compatible\n",argv[1]);
return 1;
}
/* activate the interface */
ifp->flags |= IS_NR_IFACE;
/* set quality */
if((ifp->quality=atoi(argv[2])) > 255) /*Maximum quality possible*/
ifp->quality = 255;
/*check to see if quality is not 0 */
if(ifp->quality <= 0)
ifp->quality = 1;
/* Set the minimum broadcast quality */
ifp->nr_autofloor = Nr_autofloor;
if(argc > 3)
ifp->nr_autofloor = atoi(argv[3]);
/* Check, and set the NETROM MTU - WG7J */
if((mtu = ifp->ax25->paclen - 20) < Nr_iface->mtu)
Nr_iface->mtu = mtu;
/* Poll other nodes on this interface */
nr_bcpoll(ifp);
return 0 ;
}
/* convert a null-terminated alias name to a blank-filled, upcased */
/* version. Return -1 on failure. */
int
putalias(to,from,complain)
register char *to, *from ;
int complain ;
{
int len, i ;
if((len = strlen(from)) > ALEN) {
if(complain)
tputs("alias too long - six characters max\n") ;
return -1 ;
}
for(i = 0 ; i < ALEN ; i++) {
if(i < len) {
if(islower(*from))
*to++ = toupper(*from++) ;
else
*to++ = *from++ ;
}
else
*to++ = ' ' ;
}
*to = '\0' ;
return 0 ;
}
/* Add a route */
static int
dorouteadd(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
char alias[AXALEN] ;
char dest[AXALEN] ;
unsigned quality ;
char neighbor[AXALEN] ;
struct iface *ifp;
int naddr ;
/* format alias (putalias prints error message if necessary) */
if(putalias(alias,argv[1],1) == -1)
return -1 ;
/* format destination callsign */
if(setcall(dest,argv[2]) == -1) {
tputs("bad destination callsign\n") ;
return -1 ;
}
/* find interface */
if((ifp = FindNrIface(argv[3])) == NULLIF) {
return -1;
}
/* get and check quality value */
if((quality = atoi(argv[4])) > 255) {
tputs("maximum route quality is 255\n") ;
return -1 ;
}
/* Change from 871225 -- no digis in net/rom table */
naddr = argc - 5 ;
if(naddr > 1) {
tputs("Use the ax25 route command to specify digipeaters\n") ;
return -1 ;
}
/* format neighbor address string */
setcall(neighbor,argv[5]) ;
nr_routeadd(alias,dest,ifp,quality,neighbor,1,0) ;
/* Now see if we have a route to this neighbour,
* if not add the implied route as a temporary one.
* 930527 - WG7J
*/
if(find_nrroute(neighbor) == NULLNRRTAB)
nr_routeadd("##TEMP",neighbor,ifp,quality,neighbor,0,1);
return 0;
}
/* drop a route */
static int
doroutedrop(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
char dest[AXALEN], neighbor[AXALEN] ;
struct iface *ifp;
/* format destination and neighbor callsigns */
if(setcall(dest,argv[1]) == -1) {
tputs("bad destination callsign\n") ;
return -1 ;
}
if(setcall(neighbor,argv[2]) == -1) {
tputs("bad neighbor callsign\n") ;
return -1 ;
}
/* find interface */
if((ifp = FindNrIface(argv[3])) == NULLIF) {
return -1;
}
return nr_routedrop(dest,neighbor,ifp) ;
}
/* Broadcast nodes list on named interface. */
static int
dobcnodes(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct iface *ifp;
/* find interface */
if((ifp = FindNrIface(argv[1])) == NULLIF) {
return -1;
}
nr_bcnodes(ifp) ;
return 0;
}
/* Poll nodes for routes on named interface. - WG7J */
static int
dobcpoll(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct iface *ifp;
/* find interface */
if((ifp = FindNrIface(argv[1])) == NULLIF) {
return -1;
}
nr_bcpoll(ifp) ;
return 0;
}
/* Set outbound node broadcast interval */
static int
donodetimer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2){
tprintf("Nodetimer %lu/%lu seconds\n",
read_timer(&Nodetimer)/1000L,
dur_timer(&Nodetimer)/1000L);
return 0;
}
stop_timer(&Nodetimer) ; /* in case it's already running */
Nodetimer.func = (void (*)__ARGS((void*)))donodetick;/* what to call on timeout */
Nodetimer.arg = NULLCHAR; /* dummy value */
set_timer(&Nodetimer,atoi(argv[1])*1000L); /* set timer duration */
start_timer(&Nodetimer); /* and fire it up */
return 0;
}
void
donodetick()
{
struct iface *ifp;
for(ifp=Ifaces;ifp;ifp=ifp->next)
if(ifp->flags & IS_NR_IFACE)
nr_bcnodes(ifp) ;
/* Restart timer */
start_timer(&Nodetimer) ;
}
/* Set timer for aging routes */
static int
doobsotimer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2){
tprintf("Obsotimer %lu/%lu seconds\n",
read_timer(&Obsotimer)/1000L,
dur_timer(&Obsotimer)/1000L);
return 0;
}
stop_timer(&Obsotimer) ; /* just in case it's already running */
Obsotimer.func = (void (*)__ARGS((void*)))doobsotick;/* what to call on timeout */
Obsotimer.arg = NULLCHAR; /* dummy value */
set_timer(&Obsotimer,atoi(argv[1])*1000L); /* set timer duration */
start_timer(&Obsotimer); /* and fire it up */
return 0;
}
/* Go through the routing table, reducing the obsolescence count of
* non-permanent routes, and purging them if the count reaches 0
*/
void
doobsotick()
{
register struct nrnbr_tab *np ;
register struct nrroute_tab *rp, *rpnext ;
register struct nr_bind *bp, *bpnext ;
int i ;
for(i = 0 ; i < NRNUMCHAINS ; i++) {
for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
rpnext = rp->next ; /* save in case we free this route */
/* Check all bindings for this route */
for(bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
bpnext = bp->next ; /* in case we free this binding */
if(bp->flags & NRB_PERMANENT) /* don't age these */
continue ;
if(--bp->obsocnt == 0) { /* time's up! */
if(bp->next != NULLNRBIND)
bp->next->prev = bp->prev ;
if(bp->prev != NULLNRBIND)
bp->prev->next = bp->next ;
else
rp->routes = bp->next ;
rp->num_routes-- ; /* one less binding */
np = bp->via ; /* find the neighbor */
free((char *)bp) ; /* now we can free the bind */
/* Check to see if we can free the neighbor */
if(--np->refcnt == 0) {
if(np->next != NULLNTAB)
np->next->prev = np->prev ;
if(np->prev != NULLNTAB)
np->prev->next = np->next ;
else {
Nrnbr_tab[nrhash(np->call)] = np->next ;
}
free((char *)np) ; /* free the storage */
}
}
}
if(rp->num_routes == 0) { /* did we free them all? */
if(rp->next != NULLNRRTAB)
rp->next->prev = rp->prev ;
if(rp->prev != NULLNRRTAB)
rp->prev->next = rp->next ;
else
Nrroute_tab[i] = rp->next ;
/* No more routes left !
* We should close/reset any netrom connections
* still idling for this route ! - WG7J
*/
nrresetlinks(rp);
free((char *)rp) ;
}
}
}
start_timer(&Obsotimer) ;
}
static struct cmds Nfcmds[] = {
"add", donfadd, 0, 3,
"netrom nodefilter add <neighbor> <interface> [quality]",
"drop", donfdrop, 0, 3,
"netrom nodefilter drop <neighbor> <interface>",
"mode", donfmode, 0, 0, NULLCHAR,
NULLCHAR, NULLFP, 0, 0,
"nodefilter subcommands: add drop mode",
} ;
/* nodefilter command multiplexer */
static int
donodefilter(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
if(argc < 2) {
donfdump() ;
return 0 ;
}
return subcmd(Nfcmds,argc,argv,p) ;
}
/* display a list of <callsign,interface> pairs from the filter
* list.
*/
static int
donfdump()
{
int i, column = 1 ;
struct nrnf_tab *fp ;
char buf[AXBUF] ;
for(i = 0 ; i < NRNUMCHAINS ; i++)
for(fp = Nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
pax25(buf,fp->neighbor) ;
tprintf("%-7s %-8s %-3d ",
buf,fp->iface->name, fp->quality) ;
if(column++ == 3) {
if(tputc('\n') == EOF)
return 0;
column = 1 ;
}
}
if(column != 1)
tputc('\n') ;
return 0 ;
}
/* add an entry to the filter table */
static int
donfadd(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct iface *ifp;
unsigned qual;
char neighbor[AXALEN] ;
/* format callsign */
if(setcall(neighbor,argv[1]) == -1) {
tputs("bad neighbor callsign\n") ;
return -1 ;
}
/* find interface */
if((ifp = FindNrIface(argv[2])) == NULLIF) {
return -1;
}
qual = ifp->quality; /* set default quality */
if(argc > 3)
qual = atoi(argv[3]);
return nr_nfadd(neighbor,ifp,qual) ;
}
/* drop an entry from the filter table */
static int
donfdrop(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct iface *ifp;
char neighbor[AXALEN] ;
/* format neighbor callsign */
if(setcall(neighbor,argv[1]) == -1) {
tputs("bad neighbor callsign\n") ;
return -1 ;
}
/* find interface */
if((ifp = FindNrIface(argv[2])) == NULLIF) {
return -1;
}
return nr_nfdrop(neighbor,ifp) ;
}
/* nodefilter mode subcommand */
static int
donfmode(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
if(argc < 2) {
tputs("filter mode is ") ;
switch(Nr_nfmode) {
case NRNF_NOFILTER:
tputs("none\n") ;
break ;
case NRNF_ACCEPT:
tputs("accept\n") ;
break ;
case NRNF_REJECT:
tputs("reject\n") ;
break ;
default:
tputs("some strange, unknown value\n") ;
}
return 0 ;
}
switch(argv[1][0]) {
case 'n':
case 'N':
Nr_nfmode = NRNF_NOFILTER ;
break ;
case 'a':
case 'A':
Nr_nfmode = NRNF_ACCEPT ;
break ;
case 'r':
case 'R':
Nr_nfmode = NRNF_REJECT ;
break ;
default:
tputs("modes are: none accept reject\n") ;
return -1 ;
}
return 0 ;
}
/* netrom network packet time-to-live initializer */
static int
donrttl(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setshort(&Nr_ttl,"Time to live",argc,argv);
}
/* show hidden (ie '#...') nodes or not */
static int
donrhidden(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setbool(&Nr_hidden,"Hidden nodes",argc,argv);
}
#ifdef G8BPQ
/* Emulate G8BPQ conreq/conack frames - WG7J */
static int
donrg8bpq(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setbool(&G8bpq,"G8BPQ mode",argc,argv);
}
#endif
/* allow automatic derating of netrom routes on link failure */
static int
donrderate(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
extern int Nr_derate;
return setbool(&Nr_derate,"Derate flag",argc,argv);
}
/* promiscuous acceptance of broadcasts */
static int
donrpromisc(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
extern int Nr_promisc;
return setbool(&Nr_promisc,"Promiscuous flag",argc,argv);
}
#ifdef NETROMSESSION
/* Initiate a NET/ROM transport connection */
static int
donrconnect(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
struct nrroute_tab *np;
struct sockaddr_nr lsocket, fsocket;
char alias[AXBUF];
struct session *sp;
int split = 0;
/*Make sure this comes from console - WG7J*/
if(Curproc->input != Command->input)
return 0;
#ifdef SPLITSCREEN
if(argv[0][0] == 's')
split = 1;
#endif
/* Get a session descriptor */
if((sp = newsession(argv[1],NRSESSION,split)) == NULLSESSION) {
tputs(TooManySessions);
return 1 ;
}
if((sp->s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
tputs(Nosock);
keywait(NULLCHAR,1);
freesession(sp);
return 1;
}
/* See if the requested destination is a known alias or call,
* use it if it is. Otherwize give an error message. - WG7J
*/
putalias(alias,argv[1],0);
strupr(argv[1]); /*make sure it's upper case*/
if((np = find_nrboth(alias,argv[1])) == NULLNRRTAB){
/*no such call or node alias*/
tputs("no such node\n\n");
keywait(NULLCHAR,1);
freesession(sp);
return 1;
}
/* Setup the local side of the connection */
lsocket.nr_family = AF_NETROM;
/* Set up our local username, bind would use Mycall instead */
memcpy(lsocket.nr_addr.user,Nr4user,AXALEN);
/* Putting anything else than Nr_iface->hwaddr here will not work ! */
memcpy(lsocket.nr_addr.node,Nr_iface->hwaddr,AXALEN);
/* Now bind the socket to this */
bind(sp->s,(char *)&lsocket,sizeof(struct sockaddr_nr));
/* Set up the remote side of the connection */
fsocket.nr_family = AF_NETROM;
memcpy(fsocket.nr_addr.user,np->call,AXALEN);
memcpy(fsocket.nr_addr.node,np->call,AXALEN);
fsocket.nr_family = AF_NETROM;
return tel_connect(sp, (char *)&fsocket, sizeof(struct sockaddr_nr));
}
#endif
/* Reset a net/rom connection abruptly */
static int
donrreset(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct nr4cb *cb ;
cb = MK_FP(htoi(argv[1]),8);
if(!nr4valcb(cb)){
tputs(Notval);
return 1;
}
reset_nr4(cb);
return 0;
}
/* Force retransmission on a net/rom connection */
static int
donrkick(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct nr4cb *cb ;
cb = MK_FP(htoi(argv[1]),8);
if(kick_nr4(cb) == -1) {
tputs(Notval);
return 1;
} else
return 0;
}
/* netrom transport ACK delay timer */
static int
donracktime(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setlong(&Nr4acktime,"Ack delay time (ms)",argc,argv);
}
/* netrom transport choke timeout */
static int
donrchoketime(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setlong(&Nr4choketime,"Choke timeout (ms)",argc,argv);
}
/* netrom transport initial round trip time */
static int
donrirtt(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setlong(&Nr4irtt,"Initial RTT (ms)",argc,argv);
}
/* netrom transport receive queue length limit. This is the */
/* threshhold at which we will CHOKE the sender. */
static int
donrqlimit(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setshort(&Nr4qlimit,"Queue limit (bytes)",argc,argv);
}
/* Display or change our NET/ROM username */
static int
donruser(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char buf[AXBUF];
if(argc < 2){
pax25(buf,Nr4user);
tprintf("%s\n",buf);
return 0;
}
if(setcall(Nr4user,argv[1]) == -1)
return -1;
Nr4user[ALEN] |= E;
return 0;
}
/* netrom transport maximum window. This is the largest send and */
/* receive window we may negotiate */
static int
donrwindow(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setshort(&Nr4window,"Window (frames)",argc,argv);
}
/* netrom transport maximum retries. This is used in connect and */
/* disconnect attempts; I haven't decided what to do about actual */
/* data retries yet. */
static int
donrretries(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
return setshort(&Nr4retries,"Retry limit",argc,argv);
}
/* Display the status of NET/ROM connections */
int
donrstatus(argc, argv,p)
int argc ;
char *argv[] ;
void *p;
{
int i ;
struct nr4cb *cb ;
char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
if(argc < 2) {
#ifdef UNIX
tputs("&NCB Snd-W Snd-Q Rcv-Q LUser RUser @Node State\n");
#else
tputs("&NCB Snd-W Snd-Q Rcv-Q LUser RUser @Node State\n");
#endif
for(i = 0 ; i < NR4MAXCIRC ; i++) {
if((cb = Nr4circuits[i].ccb) == NULLNR4CB)
continue ;
pax25(luser,cb->local.user) ;
pax25(ruser,cb->remote.user) ;
pax25(node,cb->remote.node) ;
#ifdef UNIX
if(tprintf("%8.8x %3d %5d %5d %9s %9s %-9s %s\n",
#else
if(tprintf("%4.4x %3d %5d %5d %9s %9s %-9s %s\n",
#endif
FP_SEG(cb), cb->nbuffered, len_q(cb->txq),
len_p(cb->rxq), luser, ruser, node,
Nr4states[cb->state]) == EOF)
break;
}
return 0 ;
}
cb = MK_FP(htoi(argv[1]),8);
if(!nr4valcb(cb)) {
tputs(Notval) ;
return 1 ;
}
donrdump(cb) ;
return 0 ;
}
/* Dump one control block */
void
donrdump(cb)
struct nr4cb *cb ;
{
char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
unsigned seq ;
struct nr4txbuf *b ;
struct timer *t ;
pax25(luser,cb->local.user) ;
pax25(ruser,cb->remote.user) ;
pax25(node,cb->remote.node) ;
tprintf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
luser, cb->mynum, cb->myid, ruser, node,
cb->yournum, cb->yourid, Nr4states[cb->state]) ;
tprintf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
len_p(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
tprintf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\n",
cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
tputs("TACK: ") ;
if(run_timer(&cb->tack))
tprintf("%lu", read_timer(&cb->tack)) ;
else
tputs("stop") ;
tprintf("/%lu ms; ", dur_timer(&cb->tack)) ;
tputs("TChoke: ") ;
if(run_timer(&cb->tchoke))
tprintf("%lu", read_timer(&cb->tchoke)) ;
else
tputs("stop") ;
tprintf("/%lu ms; ", dur_timer(&cb->tchoke)) ;
tputs("TCD: ") ;
if(run_timer(&cb->tcd))
tprintf("%lu", read_timer(&cb->tcd)) ;
else
#ifndef NR4TDISC
tputs("stop") ;
tprintf("/%lu ms", dur_timer(&cb->tcd)) ;
#else
tputs("stop") ;
tprintf("/%lu ms; ", dur_timer(&cb->tcd)) ;
tputs("TDisc: ") ;
if(run_timer(&cb->tdisc))
tprintf("%lu", (read_timer(&cb->tdisc)/1000L)) ;
else
tputs("stop") ;
tprintf("/%lu", (dur_timer(&cb->tdisc)/1000L)) ;
#endif
if(run_timer(&cb->tcd))
tprintf("; Tries: %u\n", cb->cdtries) ;
else
tputc('\n') ;
tprintf("Backoff Level %u SRTT %ld ms Mean dev %ld ms\n",
cb->blevel, cb->srtt, cb->mdev) ;
/* If we are connected and the send window is open, display */
/* the status of all the buffers and their timers */
if(cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
tputs("TxBuffers: Seq Size Tries Timer\n") ;
for(seq = cb->ackxpected ;
nr4between(cb->ackxpected, seq, cb->nextosend) ;
seq = (seq + 1) & NR4SEQMASK) {
b = &cb->txbufs[seq % cb->window] ;
t = &b->tretry ;
if(tprintf(" %3u %3d %5d %lu/%lu\n",
seq, len_p(b->data), b->retries + 1,
read_timer(t), dur_timer(t))
== EOF)
break;
}
}
}
/* netrom timers type - linear v exponential */
static int
donrtype(argc,argv,p)
int argc ;
char *argv[] ;
void *p ;
{
extern unsigned Nr_timertype;
if(argc < 2) {
tprintf("Netrom timer type is %s\n", Nr_timertype ? "linear" : "exponential" ) ;
return 0 ;
}
switch(argv[1][0]) {
case 'l':
case 'L':
Nr_timertype = 1 ;
break ;
case 'e':
case 'E':
Nr_timertype = 0 ;
break ;
default:
tputs("use: netrom timertype [linear|exponential]\n") ;
return -1 ;
}
return 0 ;
}
static int
dominquality(argc,argv,p)
int argc ;
char *argv[] ;
void *p ;
{
unsigned val ;
extern unsigned Nr_autofloor;
if(argc < 2) {
tprintf("%u\n", Nr_autofloor) ;
return 0 ;
}
val = atoi(argv[1]) ;
if(val == 0 || val > 255 ) {
tputs("maximum route quality is 255\n") ;
return 1 ;
}
Nr_autofloor = val ;
return 0 ;
}
/* Fixed and now functional, 920317 WG7J */
int
donrload(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
char buff[255];
FILE *fn;
time_t now, prev;
#ifdef notdef
long t1,t2;
int j;
#endif
int quality,obso;
int permanent,record;
struct iface *ifp;
char alias[12],dest[12],iface[12],neighbor[12],type[3],*ptr;
char destalias[ALEN+1]; /*alias in 'alias form'*/
char destcall[AXALEN]; /*in callsign (ie shifted) form */
char destneighbor[AXALEN];
if(Nr_iface == NULLIF) {
tputs("Attach netrom interface first\n") ;
return 1;
}
if((fn = fopen(Netromfile,READ_TEXT)) == NULLFILE){
/*
tputs("Can't open netrom save file!\n");
*/
return 0;
}
if(fgets(buff,sizeof(buff),fn) == NULLCHAR){ /* read the timestamp */
fclose(fn);
return 1;
}
if((strncmp(buff,"time = ",7))!= 0){
/*
tputs("Wrong node file content\n");
*/
fclose(fn);
return 1;
}
time(&now);
sscanf(buff,"time =%ld",&prev);
/*
tprintf("now = %ld , prev = %ld\n",now,prev);
*/
if(prev >= now){
/*
tputs("You traveled back in time!!\n");
*/
fclose(fn);
return 1;
}
#ifdef notdef
t1 = now - prev;
t2 = dur_timer(&Obsotimer)/1000L;
j = t1 / t2; /* recalculate obsolete count */
tprintf("%ld seconds are past ( %d obsolete scans)\n",t1,j);
#endif
while(fgets(buff,sizeof(buff),fn) != NULLCHAR){
if((ptr = strchr(buff,':')) == 0){
sscanf(buff,"%s%s%i%i%s%s"
,dest,type,&quality,&obso,iface,neighbor);
alias[0] = '\0';
} else {
*ptr = ' ';
sscanf(buff,"%s%s%s%i%i%s%s"
,alias,dest,type,&quality,&obso,iface,neighbor);
}
/*Set and check calls / alias - WG7J */
if(setcall(destcall,dest) == -1) {
/*
tprintf("Bad call %s\n",dest);
*/
continue;
}
if(setcall(destneighbor,neighbor) == -1) {
/*
tprintf("Bad call %s\n",neighbor);
*/
continue;
}
if(putalias(destalias,alias,1) == -1)
continue;
/* find interface */
if((ifp = if_lookup(iface)) == NULLIF)
continue;
/* Is it a netrom interface ? */
if(!(ifp->flags & IS_NR_IFACE))
continue;
/* get and check quality value */
if(quality > 255 || quality < Nr_autofloor) {
/*
tputs("maximum route quality is 255\n") ;
*/
continue;
}
/* Check the type of route - WG7J */
permanent = record = 0;
if(strchr(type,'P') != NULLCHAR)
permanent = 1;
else {
if(strchr(type,'R') != NULLCHAR)
record = 1;
}
nr_routeadd(destalias,destcall,ifp,quality,destneighbor, \
permanent,record) ;
}
fclose(fn);
return 0;
}
int
donrsave(argc,argv,p)
int argc ;
char *argv[] ;
void *p;
{
register struct nrroute_tab *rp ;
register struct nr_bind *bp ;
register struct nrnbr_tab *np ;
char neighbor[AXBUF] ;
register int i;
char buf[16] ;
char *cp ;
FILE *fn;
time_t now;
#ifdef __TURBOC__
if((fn = fopen(Netromfile,"wt+")) == NULLFILE){
#else
if((fn = fopen(Netromfile,"w+")) == NULLFILE){
#endif
tputs("Can't write netrom save file!\n");
return 1;
}
time(&now);
fprintf(fn,"time = %ld\n",now);
for(i = 0 ; i < NRNUMCHAINS ; i++){
for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next){
strcpy(buf,rp->alias) ;
/* remove trailing spaces */
if((cp = strchr(buf,' ')) == NULLCHAR)
cp = &buf[strlen(buf)] ;
if(cp != buf) /* don't include colon for null alias */
*cp++ = ':' ;
for(bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
pax25(cp,rp->call) ;
fprintf(fn,"%-16s ",buf) ;
np = bp->via ;
if(fprintf(fn,"%1s %3d %3d %-8s %s\n",
(bp->flags & NRB_PERMANENT ? "P" :
bp->flags & NRB_RECORDED ? "R" : "X"),
bp->quality,bp->obsocnt,
np->iface->name,
pax25(neighbor,np->call)) == EOF)
break;
}
}
}
fclose(fn);
return 0;
}
#endif /* NETROM */